package com.base.controller.coupon_api;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.base.comm.CommUrls;
import com.base.helper.VosHelper;
import com.base.po.coupon.*;
import com.base.po.coupon_prestore.CouponGoodsPrestore;
import com.base.po.coupon_prestore.CouponOrderPrestore;
import com.base.po.coupon_sdk.CouponInfoUtil;
import com.base.po.param.NetState;
import com.base.po.param.VosModelList;
import com.base.po.voip.Subscribers;
import com.base.po.voip.Users;
import com.base.po.voip_coupon.CouponPayOrder;
import com.base.po.wx.MyConfig;
import com.base.po.wx.WXPay;
import com.base.po.wx.WXPayConfig;
import com.base.po.wx.WXPayUtil;
import com.base.service.COUPON.CouponGoodsPrestoreService;
import com.base.service.COUPON.CouponOrderPrestoreService;
import com.base.service.COUPON.CouponPayOrderService;
import com.base.service.SubscribersService;
import com.base.service.UsersService;
import com.base.utils.*;
import org.jdom.JDOMException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 365优惠券支付
 *
 * @author K
 */
@Controller
@RequestMapping("/couponPay")
public class CouponPayController {

    // 用户信息
    @Autowired
    private UsersService usersService;
    @Autowired
    private SubscribersService subscribersService;
    @Autowired
    private CouponGoodsPrestoreService couponGoodsPrestoreService;
    @Autowired
    private CouponOrderPrestoreService couponOrderPrestoreService;
    @Autowired
    private CouponPayOrderService couponPayOrderService;

    // 支付宝公用变量
    private String serverUrl = "https://openapi.alipay.com/gateway.do"; // 支付宝网关 固定
    private String FORMAT = "json"; // 参数返回格式 固定
    private String CHARSET = "UTF-8"; // 编码集 固定
    private String SIGN_TYPE = "RSA2"; // 签名算法类型 固定
    private String ALIPAY_PUBLIC_KEY; // 支付宝公钥
    private String APP_ID; // appid
    private String APP_PRIVATE_KEY; // 商户私钥

    // 随机字符串
    private String randomString = PayCommonUtil.getRandomString(32);

    // 微信公用变量
    private String appid; // appid
    private String mch_id; // 商户id
    private String API_KEY; // 商户密钥

    //生成订单
    /**
     *  @Date: 2020/5/26 16:10:54
     *  @Description:
     *  @String
     *  @param  parentId 代理商ID
     *  @param userId 用户ID
     *  @param goodsId 产品ID
     *  @param number 数量
     *  @param type 1 支付宝 2 微信
     */
    @RequestMapping(value = "/insertOrder", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public NetState insertOrder(HttpServletRequest meRequest, String parentId, String userId, String goodsId, Integer number, Integer type) throws ParseException {
        NetState netState = new NetState();
        Users agent = usersService.selectByPrimaryKey(parentId);  // 代理商
        Subscribers user = subscribersService.selectByPrimaryKey(userId); // 用户
        CouponGoodsPrestore goods = couponGoodsPrestoreService.selectByPrimaryKey(goodsId);// 产品信息
        if (agent == null || agent.getDatastatus() == false
                || user == null || user.getDatastatus() == false
                || goods == null || goods.getDatastatus() == 0) {
            netState.setErrorCode(NetState.NODATA);
            netState.setData("参数异常或数据不存在");
            return netState;
        }

        // 支付金额
        Double oriUnitPrice = goods.getOfficialprices();// 原始单价
        Double unitPrice = 0.00;// 优惠单价
        try {
            // 查询商品信息
            QueryProductResponse product = CouponInfoUtil.queryProduct(goods.getId());
            if (product != null && product.getCode() == 200){
                unitPrice = product.getData().getPrice();
            }else {
                netState.setErrorCode(NetState.FEAILED);
                netState.setData("单价查询异常");
                netState.setJson(product);
                return netState;
            }
            // 查询商品库存
            QueryStockResponse stock = CouponInfoUtil.queryStock(goods.getId());
            if (stock != null && stock.getCode() == 200){
                if (number > stock.getData().getStock_num()){
                    netState.setErrorCode(NetState.FEAILED);
                    netState.setData("库存不足");
                    return netState;
                }
            }else {
                netState.setErrorCode(NetState.FEAILED);
                netState.setData("库存查询异常");
                netState.setJson(stock);
                return netState;
            }
        }catch (Exception e){
            netState.setErrorCode(NetState.SYSTEM_ERROR);
            netState.setData("数据查询异常");
            return netState;
        }
        Double oriTotalPrice = oriUnitPrice * number;// 原始总价
        Double totalPrice = unitPrice * number;// 优惠总价
        Double saleMoney = oriTotalPrice - totalPrice;// 优惠金额

        // 话费金额
        String result = VosHelper.GetVosAccount("{accounts:['" + agent.getAgentprefix() + user.getMobile() + "']}");
        VosModelList v1 = GsonUtil.getObject(result, VosModelList.class);
        // 余额过期
        if (Produce.getNowDate().after(new Date(v1.infoCustomers[0].getValidTime()))) {
            netState.setErrorCode(NetState.AMOUNT_NOT_QUERY);
            netState.setData("话费余额过期");
            return netState;
        }
        BigDecimal balance = v1.infoCustomers[0].money; // 用户余额
        // 话费余额不足
        if (balance.compareTo(new BigDecimal(saleMoney)) == -1) {
            netState.setErrorCode(NetState.AMOUNT_NOT_QUERY);
            netState.setData("话费余额不足");
            return netState;
        }

        // 订单号
        String outTradeNo = Produce.getUUID(); // 主键ID
        // 进入支付环节
        switch (type) {
            // 支付宝
            case 1:
                // 支付
                this.APP_ID = agent.getAppid(); // APPID
                this.APP_PRIVATE_KEY = agent.getKeypath(); // 商户私钥
                this.ALIPAY_PUBLIC_KEY = agent.getAlipubkey(); // 支付宝公钥
                // 未开通支付宝接口 则失败
                if (APP_ID == null || APP_PRIVATE_KEY == null || ALIPAY_PUBLIC_KEY == null || APP_ID.isEmpty()
                        || APP_PRIVATE_KEY.isEmpty() || ALIPAY_PUBLIC_KEY.isEmpty()) {
                    netState.setErrorCode(NetState.API_NOT_PER);
                    netState.setData("应用状态异常，商户未配置在线支付信息");
                    return netState;
                }
                // 获得初始化的AlipayClient
                AlipayClient alipayClient = new DefaultAlipayClient(serverUrl, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET,
                        ALIPAY_PUBLIC_KEY, SIGN_TYPE);
                // 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
                AlipayTradeAppPayRequest aliRequest = new AlipayTradeAppPayRequest();
                // 初始化支付宝信息参数
                AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
                model.setTotalAmount(totalPrice.toString()); // 订单支付金额
                model.setOutTradeNo(outTradeNo); // 商户网站唯一订单号
                model.setBody(goods.getName()); // 描述信息
                model.setSubject("特权优惠券"); // 订单标题
                model.setTimeoutExpress("90m"); // 最晚付款时间 后台固定
                model.setProductCode("QUICK_MSECURITY_PAY"); // 销售产品码 后台固定
                model.setGoodsType("1"); // 商品主类型:0-虚拟类商品 1-实物类商品 后台固定
                // 传入参数
                aliRequest.setBizModel(model);
                // 异步通知
                aliRequest.setNotifyUrl(CommUrls.THISSERVER + "couponPay/aliNotify");

                try {
                    // 这里和普通的接口调用不同，使用的是sdkExecute
                    AlipayTradeAppPayResponse response = alipayClient.sdkExecute(aliRequest);
                    // 生成订单
                    couponPayOrderService.insertSelective(new CouponPayOrder(outTradeNo, agent.getId(), user.getId(), goods.getId(),
                            goods.getName(), oriUnitPrice, oriTotalPrice, unitPrice, totalPrice, number, (byte)0, Produce.getNowDate()));
                    netState.setErrorCode(NetState.SUCCESS_CONN);
                    netState.setData("调用支付宝成功");
                    netState.setJson(response.getBody()); // 写入JSON
                } catch (AlipayApiException e) {
                    e.printStackTrace();
                    // 调用失败
                    netState.setErrorCode(NetState.SIGN_ERROR);
                    netState.setData("非法操作");
                }
                break;
            // 微信
            case 2:
                // 支付
                this.appid = agent.getWxappid(); // APPID
                this.mch_id = agent.getWxmchid(); // 商户ID
                this.API_KEY = agent.getWxapikey(); // 密钥
                // 未开通微信接口 则失败
                if (appid == null || mch_id == null || API_KEY == null || appid.isEmpty() || mch_id.isEmpty()
                        || API_KEY.isEmpty()) {
                    netState.setErrorCode(NetState.API_NOT_PER);
                    netState.setData("应用状态异常，商户未配置在线支付信息");
                    return netState;
                }
                // 一次签名 生成预付款信息
                SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();
                parameterMap.put("appid", appid); // 应用appid
                parameterMap.put("mch_id", mch_id); // 商户号
                parameterMap.put("nonce_str", randomString); // 随机字符串
                parameterMap.put("body", goods.getName()); // 商品描述
                parameterMap.put("out_trade_no", outTradeNo); // 商户订单号
                parameterMap.put("total_fee",
                        new DecimalFormat("0").format(new BigDecimal(totalPrice).multiply(new BigDecimal(100)))); // 接口中参数支付金额单位为【分】，参数值不能带小数，所以乘以100
                parameterMap.put("spbill_create_ip", IP.getIpAddr(meRequest)); // 终端IP

                parameterMap.put("notify_url", CommUrls.THISSERVER + "couponPay/wxNotify"); // 通知地址
                parameterMap.put("trade_type", "APP"); // 交易类型
                String sign1 = PayCommonUtil.createSign("UTF-8", parameterMap, API_KEY); // 组装签名
                parameterMap.put("sign", sign1); // 签名
                String requestXML = PayCommonUtil.getRequestXml(parameterMap); // 组装XML
                String wxResult = PayCommonUtil.httpsRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST",
                        requestXML); // XML
                Map<String, String> map = null;
                try {
                    map = WXPayUtil.xmlToMap(wxResult);
                } catch (JDOMException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                if (map == null || map.get("prepay_id") == null || map.get("prepay_id").isEmpty()) {
                    netState.setErrorCode(NetState.PARAMS_ERROR);
                    netState.setData("交易状态异常，微信支付接口调取失败");
                    return netState;
                }

                try {
                    // 二次签名 返回App调用微信支付
                    SortedMap<String, Object> finalpackage = new TreeMap<String, Object>();
                    finalpackage.put("appid", appid); // 应用ID
                    finalpackage.put("partnerid", mch_id); // 商户号
                    Long time = (System.currentTimeMillis() / 1000);
                    finalpackage.put("timestamp", time.toString()); // 时间戳
                    finalpackage.put("noncestr", map.get("nonce_str")); // 随机字符串
                    finalpackage.put("prepayid", map.get("prepay_id")); // 预支付交易会话ID
                    finalpackage.put("package", "Sign=WXPay"); // 扩展字段
                    String sign2 = PayCommonUtil.createSign("UTF-8", finalpackage, API_KEY); // 组装签名
                    finalpackage.put("sign", sign2); // 签名
                    // 生成订单
                    couponPayOrderService.insertSelective(new CouponPayOrder(outTradeNo, agent.getId(), user.getId(), goods.getId(),
                            goods.getName(), oriUnitPrice, oriTotalPrice, unitPrice, totalPrice, number, (byte)0, Produce.getNowDate()));
                    netState.setErrorCode(NetState.SUCCESS_CONN);
                    netState.setData("调用微信成功");
                    netState.setJson(finalpackage); // 写入JSON
                } catch (Exception e) {
                    e.printStackTrace();
                    netState.setErrorCode(NetState.PARAMS_ERROR);
                    netState.setData("交易状态异常，微信支付接口调取失败");
                }
                break;
        }
        return netState;
    }

    /**
     * 支付宝异步返回结果
     *
     * @param request  获取支付宝返回的信息
     * @param response 返回给支付宝的信息
     */
    @RequestMapping(value = "/aliNotify", method = {RequestMethod.POST, RequestMethod.GET})
    public void alNotify2(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 获取支付宝POST过来的反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = iter.next();
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++)
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            // 乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
            params.put(name, valueStr);
        }
        // 在通知返回参数列表中，除去sign、sign_type两个参数外，凡是通知返回回来的参数皆是待验签的参数。
        boolean signVerified = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET, SIGN_TYPE);
        // 验证签名
        sign:
        if (signVerified) {
            // 验证支付状态
            if (params.get("trade_status").equals("TRADE_SUCCESS")) {
                // 订单信息
                CouponPayOrder order = couponPayOrderService.selectByPrimaryKey(params.get("out_trade_no"));
                // 判断该订单是否存在
                if (order == null) {
                    break sign;
                }
                Double aliPay = order.getTotalprice(); // 订单支付创建时金额
                BigDecimal total_amount = new BigDecimal(params.get("total_amount")); // 实际支付订单金额
                // 如果订单金额不相等 则验证失败
                if (new BigDecimal(aliPay).compareTo(total_amount) != 0) {
                    break sign;
                }

                // 判断完成 ->更新支付订单
                order.setStatus((byte) 1);
                order.setPaytime(Produce.getNowDate());
                couponPayOrderService.updateByPrimaryKeySelective(order);

                // 判断完成 ->更新优惠券订单
                payOrder(order);

                // 扣除话费
                Double money_derate = order.getOritotalprice() - order.getTotalprice();
                Users agent = usersService.selectByPrimaryKey(order.getParentid());
                Subscribers user = subscribersService.selectByPrimaryKey(order.getUserid());
                Double money = money_derate * -1; // 需要扣除的费用
                VosHelper.PayVosAccount("{\"ownerName\":\"" + agent.getAgentprefix() + user.getMobile()
                        + "\",\"ownerType\":\"2\",\"money\":\"" + money + "\",\"memo\":\"" + user.getUsername()
                        + "，用户365优惠券扣费" + money + "元\"}");
            }
            // 返回success
            response.getWriter().print("success"); // 固定 不可删除
        } else {
            // 返回fail
            response.getWriter().print("fail"); // 固定 不可删除
        }
    }

    /**
     * 微信异步返回结果
     *
     * @param request  获取支付宝返回的信息
     * @param response 返回给支付宝的信息
     */
    @RequestMapping(value = "/wxNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String wxNotify2(HttpServletRequest request, HttpServletResponse response) throws Exception {
        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        String notifyData = new String(outSteam.toByteArray(), StandardCharsets.UTF_8); // 支付结果通知的xml格式数据
        outSteam.close();
        inStream.close();
        // 微信提供的验签
        WXPayConfig config = new MyConfig(appid, mch_id, API_KEY); // 配置信息
        WXPay wxpay = new WXPay(config);
        Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData); // 转换成map
        Map<String, String> return_data = new HashMap<String, String>(); // 返回
        boolean wxSign = wxpay.isPayResultNotifySignatureValid(notifyMap);
        if (notifyMap.get("trade_type").equals("MWEB")) {
            wxSign = true;
        }
        // 验证签名
        sign:
        if (wxSign) {
            // 验证支付状态
            if (notifyMap.get("result_code").equals("SUCCESS")) {
                // 继续商户自身业务处理
                CouponPayOrder order = couponPayOrderService.selectByPrimaryKey(notifyMap.get("out_trade_no"));
                // 判断该订单是否存在
                if (order == null) {
                    break sign;
                }
                Double aliPay = order.getTotalprice(); // 订单支付创建时金额
                BigDecimal total_amount = new BigDecimal(notifyMap.get("total_fee")); // 实际支付订单金额
                // 如果订单金额不相等 则验证失败
                if (new BigDecimal(aliPay).compareTo(total_amount) != 0) {
                    break sign;
                }

                // 判断完成 ->更新支付订单
                order.setStatus((byte) 1);
                order.setPaytime(Produce.getNowDate());
                couponPayOrderService.updateByPrimaryKeySelective(order);

                // 判断完成 ->更新优惠券订单
                payOrder(order);

                // 扣除话费
                Double money_derate = order.getOritotalprice() - order.getTotalprice();
                Users agent = usersService.selectByPrimaryKey(order.getParentid());
                Subscribers user = subscribersService.selectByPrimaryKey(order.getUserid());
                Double money = money_derate * -1; // 需要扣除的费用
                VosHelper.PayVosAccount("{\"ownerName\":\"" + agent.getAgentprefix() + user.getMobile()
                        + "\",\"ownerType\":\"2\",\"money\":\"" + money + "\",\"memo\":\"" + user.getUsername()
                        + "，用户365优惠券扣费" + money + "元\"}");
            }
            // 返回SUCCESS
            return_data.put("return_code", "SUCCESS"); // 固定 不可删除
            return_data.put("return_msg", "OK");
        } else {
            // 签名错误，如果数据里没有sign字段，也认为是签名错误
            // 返回FAIL
            return_data.put("return_code", "FAIL"); // 固定 不可删除
            return_data.put("return_msg", "return_code不正确");
        }
        return StringUtil.GetMapToXML(return_data);
    }

    // 创建订单
    public void payOrder(CouponPayOrder order) throws ParseException {
        // 时间转换对象
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 创建订单id
        String payOrderId = order.getId();
        PayOrderResponse pay = CouponInfoUtil.payOrder(order.getProductid(), payOrderId, order.getNumber().toString());
        if (pay != null && pay.getCode() == 200){
            List<PayOrderResponseData> payOrders = pay.getData();
            for (PayOrderResponseData payOrder : payOrders){
                CouponOrderPrestore couponOrder = new CouponOrderPrestore();
                couponOrder.setId(payOrder.getOut_trade_no());
                couponOrder.setOrderno(payOrder.getOrder_no());
                couponOrder.setParentid(order.getParentid());
                couponOrder.setUserid(order.getUserid());
                couponOrder.setProductid(payOrder.getProduct_id());
                couponOrder.setCardtype(payOrder.getCard_type());
                couponOrder.setLinkurl(payOrder.getLink_url());
                couponOrder.setUniquecode(payOrder.getUnique_code());
                couponOrder.setCardno(payOrder.getCard_no());
                couponOrder.setCardpwd(payOrder.getCard_pwd());
                couponOrder.setCouponcreatetime(dateFormat.parse(payOrder.getCreate_time()));
                couponOrder.setOrdercreatetime(Produce.getNowDate());
                couponOrder.setOrderstatus(queryOrder(payOrder.getOrder_no()));
                couponOrderPrestoreService.insertSelective(couponOrder);
            }
        }
    }

    // 订单状态查询
    public int queryOrder(String orderNo){
        Integer orderStatus = null;

        QueryOrderResponse query = CouponInfoUtil.queryOrder(orderNo);
        if (query != null && query.getCode() == 200){
            orderStatus = query.getData();
        }

        return orderStatus == null ? -1 : orderStatus;
    }

    //TODO 测试接口 2020-06-04 14:37:45
    @RequestMapping(value = "/testPayOrder", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public NetState insertOrder(String couponPayOrderId) throws ParseException {
        NetState netState = new NetState();

        CouponPayOrder order = couponPayOrderService.selectByPrimaryKey(couponPayOrderId);
        payOrder(order);

        return netState;
    }
}
